package com.vben.common.redis.service;

import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Spring Redis 工具类 (适配Spring3.3.8+ & Java17)
 */
@Component
@SuppressWarnings({"unchecked", "unused"})
public class RedisService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    /* ------------------------- 通用操作 ------------------------- */

    /**
     * 设置Key生命周期
     *
     * @param key     Redis键
     * @param timeout 过期时间
     * @param unit    时间单位
     * @return 是否设置成功
     */
    public boolean expire(String key, long timeout, TimeUnit unit) {
        Assert.hasText(key, "Key must not be null or empty");
        return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, unit));
    }

    public boolean expire(String key, long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取剩余存活时间(秒)
     */
    public long getExpire(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 删除单个Key
     */
    public boolean delete(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        return Boolean.TRUE.equals(redisTemplate.delete(key));
    }

    /**
     * 批量删除Keys
     *
     * @return 成功删除的数量
     */
    public long deleteBatch(Collection<String> keys) {
        Assert.notEmpty(keys, "Keys must not be empty");
        return redisTemplate.delete(keys);
    }

    /**
     * 是否存在Key
     */
    public boolean hasKey(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }

    /* ------------------------- String操作 ------------------------- */

    /**
     * 设置值
     */
    public <T> void set(String key, T value) {
        Assert.hasText(key, "Key must not be null or empty");
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置值并指定过期时间
     */
    public <T> void set(String key, T value, long timeout, TimeUnit unit) {
        Assert.hasText(key, "Key must not be null or empty");
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 安全获取值(使用Optional包装)
     */
    public <T> Optional<T> get(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        return Optional.ofNullable((T) redisTemplate.opsForValue().get(key));
    }

    /**
     * 值递增
     */
    public long increment(String key, long delta) {
        Assert.hasText(key, "Key must not be null or empty");
        Long value = redisTemplate.opsForValue().increment(key, delta);
        return value != null ? value : 0L;
    }

    /**
     * 值递减
     */
    public long decrement(String key, long delta) {
        Assert.hasText(key, "Key must not be null or empty");
        return increment(key, -delta);
    }

    /* ------------------------- Hash操作 ------------------------- */

    public <HK, HV> void putHash(String key, HK hashKey, HV value) {
        Assert.hasText(key, "Key must not be null or empty");
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    public <HK, HV> void putAllHash(String key, Map<HK, HV> map) {
        Assert.hasText(key, "Key must not be null or empty");
        Assert.notEmpty(map, "Map must not be empty");
        redisTemplate.opsForHash().putAll(key, map);
    }

    public <HK, HV> Optional<HV> getHash(String key, HK hashKey) {
        Assert.hasText(key, "Key must not be null or empty");
        HashOperations<String, HK, HV> ops = redisTemplate.opsForHash();
        return Optional.ofNullable(ops.get(key, hashKey));
    }

    public <HK, HV> Map<HK, HV> getAllHash(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        HashOperations<String, HK, HV> ops = redisTemplate.opsForHash();
        return ops.entries(key);
    }

    public <HK> boolean deleteHash(String key, HK... hashKeys) {
        Assert.hasText(key, "Key must not be null or empty");
        Assert.notEmpty(hashKeys, "HashKeys must not be empty");
        Long count = redisTemplate.opsForHash().delete(key, (Object[]) hashKeys);
        return count > 0;
    }

    /* ------------------------- List操作 ------------------------- */

    public <T> long pushList(String key, List<T> list) {
        Assert.hasText(key, "Key must not be null or empty");
        Assert.notEmpty(list, "List must not be empty");
        Long count = redisTemplate.opsForList().rightPushAll(key, list.toArray());
        return count != null ? count : 0L;
    }

    public <T> Optional<List<T>> getList(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        List<Object> values = redisTemplate.opsForList().range(key, 0, -1);
        return Optional.ofNullable(values)
                .map(list -> list.stream()
                        .map(e -> (T) e)
                        .collect(Collectors.toList()));
    }

    public <T> Optional<List<T>> getListRange(String key, long start, long end) {
        Assert.hasText(key, "Key must not be null or empty");
        List<Object> values = redisTemplate.opsForList().range(key, start, end);
        return Optional.ofNullable(values)
                .map(list -> list.stream()
                        .map(e -> (T) e)
                        .collect(Collectors.toList()));
    }

    public Optional<Long> getListSize(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        return Optional.ofNullable(redisTemplate.opsForList().size(key));
    }

    /* ------------------------- Set操作 ------------------------- */

    public <T> long addSet(String key, Set<T> set) {
        Assert.hasText(key, "Key must not be null or empty");
        Assert.notEmpty(set, "Set must not be empty");
        Long count = redisTemplate.opsForSet().add(key, set.toArray());
        return count != null ? count : 0L;
    }

    public <T> Optional<Set<T>> getSet(String key) {
        Assert.hasText(key, "Key must not be null or empty");
        Set<Object> members = redisTemplate.opsForSet().members(key);
        return Optional.ofNullable(members)
                .map(m -> m.stream()
                        .map(e -> (T) e)
                        .collect(Collectors.toSet()));
    }

    /* ------------------------- 高级操作 ------------------------- */

    /**
     * 模式匹配Keys
     */
    public Set<String> keys(String pattern) {
        Assert.hasText(pattern, "Pattern must not be null or empty");
        return redisTemplate.keys(pattern);
    }

    /**
     * 获取Redis原生模板（用于复杂操作）
     */
    public RedisTemplate<String, Object> getNativeTemplate() {
        return redisTemplate;
    }
}